﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.ComponentModel;
using MiniFox.Infrastructure.Attributes;
using MiniFox.Infrastructure;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;

namespace MiniFox.Data.Mapping
{
    /// <summary>
    /// 表映射类型
    /// </summary>
    public class TableMapping : ITableMapping
    {
        #region static members

        static readonly object lock_flag;
        static readonly Dictionary<string, ITableMapping> _tableMappings;

        static TableMapping()
        {
            lock_flag = new object();
            _tableMappings = new Dictionary<string, ITableMapping>();
        }
        /// <summary>
        /// 根据类型获得表映射对象
        /// </summary>
        /// <param name="type">需要映射的类型</param>
        /// <returns></returns>
        public static ITableMapping GetTableMapping(Type type)
        {
            ITableMapping tableMapping = null;
            string key = type.AssemblyQualifiedName;
            lock (lock_flag)
            {
                if (_tableMappings.ContainsKey(key))//检查全局字典是否已缓存表映射
                    tableMapping = _tableMappings[key];
                if (tableMapping == null)
                {
                    var tableAtt = type.GetCustomAttribute<TableAttribute>();//获得表映射描述特性
                    if (tableAtt != null)
                    {
                        #region tablemapping
                        //未设置映射表名时，直接使用类名
                        string sourceTable = (string.IsNullOrEmpty(tableAtt.Name) ? type.Name : tableAtt.Name);

                        var tMapping = new TableMapping(sourceTable, type.FullName);

                        foreach (PropertyInfo property in type.GetProperties())
                        {
                            var colAtt = property.GetCustomAttribute<ColumnAttribute>();//根据属性获得列映射描述特性
                            if (colAtt == null)//缺少列映射描述特性时，忽略
                                continue;

                            string colName = string.IsNullOrEmpty(colAtt.Name) ? property.Name : colAtt.Name;
                            ColumnMapping mapping = (ColumnMapping)tMapping.ColumnMappings.Add(colName, property.Name);

                            KeyAttribute keyAttribute = property.GetCustomAttribute<KeyAttribute>();
                            mapping.PrimaryKey = keyAttribute != null;
                            
                            //mapping.Nullable = colAtt.Nullable;
                            //mapping.Unique = colAtt.IsUnique;

                            EditableAttribute editableAttribute = property.GetCustomAttribute<EditableAttribute>();
                            mapping.ReadOnly = (editableAttribute != null && !editableAttribute.AllowEdit);
                            mapping.Type = Type.GetTypeCode(property.PropertyType);


                            DisplayAttribute displayAttribute = property.GetCustomAttribute<DisplayAttribute>();
                            if (displayAttribute != null)
                            {
                                mapping.DisplayCaption = displayAttribute.ShortName ?? displayAttribute.Name;
                            }
                            
                            mapping.Ordinal = colAtt.Order;

                            if (mapping.PrimaryKey)
                                tMapping.PrimaryKeys.Add(mapping.DataSetColumn);

                            IncrementSequenceAttribute autoIncrement = property.GetCustomAttribute<IncrementSequenceAttribute>();
                            mapping.AutoIncrement = (autoIncrement != null);
                            
                        }
                        tableMapping = tMapping;
                        _tableMappings.Add(key, tableMapping);
                        #endregion
                    }
                    else //缺少表映射描述特性时，直接创建ADO.NET原生表映射对象
                    {
                        tableMapping = new DataTableMapping(type.Name, type.FullName);
                        foreach (PropertyInfo property in type.GetProperties())
                        {
                            string colName = property.Name;
                            DataColumnMapping mapping = (DataColumnMapping)tableMapping.ColumnMappings.Add(colName, colName);
                        }
                        _tableMappings.Add(key, tableMapping);
                    }
                }
            }
            return tableMapping;
        }
        /// <summary>
        /// 根据泛型获得表映射对象
        /// </summary>
        /// <typeparam name="T">需要映射的类型</typeparam>
        /// <returns></returns>
        public static ITableMapping GetTableMapping<T>()
        {
            return GetTableMapping(typeof(T));
        }

        /// <summary>
        /// TableMapping对象隐式转换为ADO.NET原生表映射对象（DataTableMapping类型）
        /// </summary>
        /// <param name="tableMapping"></param>
        /// <returns></returns>
        public static implicit operator DataTableMapping(TableMapping tableMapping)
        {
            DataTableMapping mapping = new DataTableMapping(tableMapping.SourceTable, tableMapping.DataSetTable);
            foreach (IColumnMapping cMapping in tableMapping.ColumnMappings)
            {
                DataColumnMapping cm = mapping.ColumnMappings.Add(cMapping.SourceColumn, cMapping.DataSetColumn);
            }
            return mapping;
        }

        #endregion

        string _dataSetTable;
        string _sourceTable;
        ColumnMappingCollection _columnMappings;
        List<string> _primaryKeys;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceTable">数据库表名</param>
        /// <param name="dataSetTable">数据集表名</param>
        internal TableMapping(string sourceTable, string dataSetTable)
        {
            _dataSetTable = dataSetTable;
            _sourceTable = sourceTable;
            _columnMappings = new ColumnMappingCollection(this);
            _primaryKeys = new List<string>();
        }

        /// <summary>
        /// 主键集合
        /// </summary>
        public List<string> PrimaryKeys
        {
            get
            {
                return _primaryKeys;
            }
        }

        #region ITableMapping 成员
        /// <summary>
        /// 获取列映射集合
        /// </summary>
        public IColumnMappingCollection ColumnMappings
        {
            get { return _columnMappings; }
        }
        /// <summary>
        /// 数据集(对象)表名
        /// </summary>
        public string DataSetTable
        {
            get
            {
                return _dataSetTable;
            }
            set
            {
                _dataSetTable = value;
            }
        }
        /// <summary>
        /// 数据库(源)表名
        /// </summary>
        public string SourceTable
        {
            get
            {
                return _sourceTable;
            }
            set
            {
                _sourceTable = value;
            }
        }

        #endregion


    }
}
